package com.smallyu.order.utils;

import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: small-yu
 * @Package: com.smallyu.order.utils
 * @Project: order
 * @Date: 2024/4/16
 * @Time: 2:16
 * Redis工具类
 */
@Component
public class YuRedisUtils {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 返回key的存活时间
     * @param ttl
     * @param timeUnit
     * @return
     */
    public Long getTtlCount(final String ttl,final TimeUnit timeUnit){
        if (timeUnit != null){
            return redisTemplate.getExpire(ttl,timeUnit);
        }
        return redisTemplate.getExpire(ttl);
    }

    /**
     * 是否存在对应key值
     * @param key
     * @return
     */
    public Boolean isExist(final String key){
        return redisTemplate.hasKey(key);
    }

    /**
     * 返回对应匹配key值
     * @param pattern
     * @return
     */
    public Set keys(final String pattern){
        return redisTemplate.keys(pattern);
    }

    /**
     * 设置过期值
     * @param key
     * @param timeOut
     * @param timeUnit
     * @return
     */
    public Boolean expire(final String key,final Integer timeOut,final TimeUnit timeUnit){
        return redisTemplate.expire(key,timeOut,timeUnit);
    }

    /**
     * 存储基本对象
     * @param key
     * @param value
     * @param <T>
     */
    public <T> void setObject(final String key,final T value){
        redisTemplate.opsForValue().set(key,value);
    }

    /**
     * 存储基本对象-附加过期时间
     * @param key
     * @param value
     * @param <T>
     */
    public <T> void setObject(final String key,final T value,final Integer timeOut,final TimeUnit timeUnit){
        redisTemplate.opsForValue().set(key,value,timeOut,timeUnit);
    }

    /**
     * 叠加数据
     * @param key
     * @param val
     */
    public Integer appendValue(final String key,final String val){
        return redisTemplate.opsForValue().append(key,val);
    }

    /**
     * 递增数值
     * @param key
     * @return
     */
    public Long incrementNumber(final String key){
        return redisTemplate.opsForValue().increment(key);
    }

    /**
     * 递增数值
     * @param key
     * @return
     */
    public Long incrementNumber(final String key,final Long val){
        return redisTemplate.opsForValue().increment(key,val);
    }

    /**
     * 递减数值
     * @param key
     * @return
     */
    public Long decrementNumber(final String key){
        return redisTemplate.opsForValue().decrement(key);
    }

    /**
     * 递减数值
     * @param key
     * @return
     */
    public Long decrementNumber(final String key,final Long val){
        return redisTemplate.opsForValue().decrement(key,val);
    }

    /**
     * 获取对象
     * @param key
     * @param <T>
     * @return
     */
    public <T> T getObject(final String key){
        ValueOperations<String,T> operations = redisTemplate.opsForValue();
        return operations.get(key);
    }

    /**
     * 获取对象的同时存储对象
     * @param key
     * @param val
     * @param <T>
     * @return
     */
    public <T> T getObjectAndSet(final String key,final T val){
        ValueOperations<String,T> operations = redisTemplate.opsForValue();
        return operations.getAndSet(key,val);
    }

    /**
     * 若无对应key则存储对象且返回true,否则返回false
     * @param key
     * @param val
     * @param <T>
     * @return
     */
    public <T> Boolean setObjectIfAbsent(final String key,final T val){
        return redisTemplate.opsForValue().setIfAbsent(key,val);
    }

    /**
     * 若无对应key则存储对象且返回true,否则返回false
     * @param key
     * @param val
     * @param <T>
     * @return
     */
    public <T> Boolean setObjectIfAbsent(final String key,final T val,final Integer timeOut,final TimeUnit timeUnit){
        return redisTemplate.opsForValue().setIfAbsent(key,val,timeOut,timeUnit);
    }

    /**
     * 从左添加对象入List
     * @param key
     * @param val
     * @param <T>
     */
    @SafeVarargs
    public final <T> Long leftPushList(final String key, T... val){
        return redisTemplate.opsForList().leftPushAll(key,val);
    }

    /**
     * 从左添加对象入List,如果有对应键则返回1,否则操作失败返回0
     * @param key
     * @param val
     * @param <T>
     */
    @SafeVarargs
    public final <T> Long leftPushListIfPresent(final String key, T... val){
        return redisTemplate.opsForList().leftPushIfPresent(key,val);
    }

    /**
     * 从右添加对象入List
     * @param key
     * @param val
     * @param <T>
     */
    @SafeVarargs
    public final <T> Long rightPushList(final String key, T... val){
        return redisTemplate.opsForList().rightPushAll(key,val);
    }

    /**
     * 从右添加对象入List,如果有对应键则返回1,否则操作失败返回0
     * @param key
     * @param val
     * @param <T>
     */
    @SafeVarargs
    public final <T> Long rightPushListIfPresent(final String key, T... val){
        return redisTemplate.opsForList().rightPushIfPresent(key,val);
    }

    /**
     * 从左提取对象
     * @param key
     * @param <T>
     * @return
     */
    public <T> Object leftPopList(final String key){
        return redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 从右提取对象
     * @param key
     * @return
     */
    public Object rightPopList(final String key){
        return redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 获取List对象
     * @param key
     * @param <T>
     * @return
     */
    public <T> List<T> getListObject(final String key){
        return redisTemplate.opsForList().range(key,0,-1);
    }

    /**
     * 添加Set数据
     * @param key
     * @param dataSet
     * @param <T>
     */
    public <T> void setSetObject(final String key,final Set<T> dataSet){
        SetOperations operations = redisTemplate.opsForSet();
        Iterator<T> iterator = dataSet.iterator();
        while (iterator.hasNext()){
            operations.add(key,iterator.next());
        }
    }

    /**
     * 返回对应key值的Set容量
     * @param key
     * @return
     */
    public Long getSetSize(final String key){
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * 返回多个key值对应Set的差集
     * @param key1
     * @param key2
     * @param <T>
     * @return
     */
    public <T> Set<T> getDifferentSet(final String key1,final List<T> key2){
        return redisTemplate.opsForSet().difference(key1,key2);
    }

    /**
     * 返回多个key值对应Set的差集并存储新的key值
     * @param key1
     * @param key2
     * @param <T>
     * @return
     */
    public <T> Long getDifferentSetAndSetNewKey(final String key1,final List<T> key2,final String destinationKey){
        return redisTemplate.opsForSet().differenceAndStore(key1,key2,destinationKey);
    }

    /**
     * 返回多个key值对应Set的交集
     * @param key1
     * @param key2
     * @param <T>
     * @return
     */
    public <T> Set<T> getInterSet(final String key1,final List<T> key2){
        return redisTemplate.opsForSet().intersect(key1,key2);
    }

    /**
     * 返回多个key值对应Set的交集并存储新的key值
     * @param key1
     * @param key2
     * @param <T>
     * @return
     */
    public <T> Long getInterSetAndSetNewKey(final String key1,final List<T> key2,final String destinationKey){
        return redisTemplate.opsForSet().intersectAndStore(key1,key2,destinationKey);
    }

    /**
     * 返回多个key值对应Set的并集
     * @param key1
     * @param key2
     * @param <T>
     * @return
     */
    public <T> Set<T> getUnionSet(final String key1,final List<T> key2){
        return redisTemplate.opsForSet().union(key1,key2);
    }

    /**
     * 返回多个key值对应Set的并集并存储新的key值
     * @param key1
     * @param key2
     * @param <T>
     * @return
     */
    public <T> Long getUnionSetAndSetNewKey(final String key1,final List<T> key2,final String destinationKey){
        return redisTemplate.opsForSet().unionAndStore(key1,key2,destinationKey);
    }

    /**
     * 判断某对象是否在对应key值Set容器里
     * @param key
     * @param val
     * @param <T>
     * @return
     */
    public <T> Boolean isMembers(final String key,final T val){
        return redisTemplate.opsForSet().isMember(key,val);
    }

    /**
     * 获取对应key值的Set
     * @param key
     * @param <T>
     * @return
     */
    public <T> Set<T> getSetObject(final String key){
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 将Set中的某些数据移动到另一个Set里
     * @param key1
     * @param key2
     * @param val
     * @param <T>
     * @return
     */
    @SafeVarargs
    public final <T> Boolean moveSetToOther(final String key1, final String key2, T... val){
        return redisTemplate.opsForSet().move(key1,key2,val);
    }

    /**
     * 添加Map数据
     * @param key
     * @param val
     * @param <T>
     */
    public <T> void setMapObject(final String key,final Map<String,T> val){
        if (val != null){
            redisTemplate.opsForHash().putAll(key,val);
        }
    }

    /**
     * 如果添加Map数据,如果不存在对应key返回true,否则返回false
     * @param key
     * @param val
     * @param <T>
     */
    public <T> Boolean setMapObjectIfAbsent(final String key,final Map<String,T> val){
            try{
                if (val != null){
                    Set<Map.Entry<String, T>> entries = val.entrySet();
                    Iterator<Map.Entry<String, T>> iterator = entries.iterator();
                    while (iterator.hasNext()){
                        Map.Entry<String, T> next = iterator.next();
                        redisTemplate.opsForHash().putIfAbsent(key,next.getKey(),next.getValue());
                    }
                    return true;
                }
            }catch (Exception e){
                e.printStackTrace();
                return false;
            }
        return false;
    }

    /**
     * 获取Map对象
     * @param key
     * @param <T>
     * @return
     */
    public <T> Map<String,T> getMapObject(final String key){
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 往Map中存入数据
     * @param key
     * @param hk
     * @param hv
     * @param <T>
     */
    public <T> void setMapValue(final String key,final String hk,final T hv){
        redisTemplate.opsForHash().put(key,hk,hv);
    }

    /**
     * 获取Map中的value值
     * @param key
     * @param hk
     * @param <T>
     * @return
     */
    public <T> T getMapValue(final String key,final String hk){
        HashOperations<String,String,T> operations = redisTemplate.opsForHash();
        return operations.get(key,hk);
    }

    /**
     * 删除Map中的数据
     * @param key
     * @param hk
     * @return
     */
    @SafeVarargs
    public final <T> Long deleteMapValue(final String key, final T... hk){
        return redisTemplate.opsForHash().delete(key, hk);
    }

    /**
     * 获取多个Map中的value值
     * @param key
     * @param hk
     * @param <T>
     * @return
     */
    public <T> List<T> getMultiMapValue(final String key,final Collection<T> hk){
        HashOperations operations = redisTemplate.opsForHash();
        return operations.multiGet(key,hk);
    }

    /**
     * 设置ZSet对象
     * @param key
     * @param val
     * @param <T>
     * @return
     */
    public <T> Long setZSetObject(final String key,LinkedHashSet<T> val){
        return redisTemplate.opsForZSet().add(key,val);
    }

    /**
     * 获取Zset对象
     * @param key
     * @param <T>
     * @return
     */
    public <T> Set<T> getZSetValueAsc(final String key){
        return redisTemplate.opsForZSet().range(key,0,-1);
    }

}
